<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI对话助手 - DeepSeek-R1</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#6366f1',
                        secondary: '#8b5cf6',
                        light: '#f9fafb',
                        dark: '#1f2937',
                        success: '#10b981',
                        error: '#ef4444'
                    }
                }
            }
        }
    </script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

        body {
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            background: linear-gradient(135deg, #f0f9ff 0%, #fdf2f8 100%);
        }

        .message-container {
            scroll-behavior: smooth;
            background: rgba(255, 255, 255, 0.7);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(229, 231, 235, 0.5);
        }

        .message-container::-webkit-scrollbar {
            width: 8px;
        }

        .message-container::-webkit-scrollbar-track {
            background: rgba(241, 245, 249, 0.5);
        }

        .message-container::-webkit-scrollbar-thumb {
            background: #c7d2fe;
            border-radius: 4px;
        }

        .typing-indicator {
            display: inline-block;
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: #6b7280;
            margin-right: 4px;
            animation: typing 1.4s infinite ease-in-out both;
        }

        .typing-indicator:nth-child(1) {
            animation-delay: 0s;
        }

        .typing-indicator:nth-child(2) {
            animation-delay: 0.2s;
        }

        .typing-indicator:nth-child(3) {
            animation-delay: 0.4s;
        }

        @keyframes typing {
            0%, 60%, 100% {
                transform: translateY(0);
            }
            30% {
                transform: translateY(-6px);
            }
        }

        .ai-response pre {
            background-color: #f3f4f6;
            padding: 12px;
            border-radius: 8px;
            overflow-x: auto;
            margin: 8px 0;
        }

        .ai-response code {
            background-color: #f3f4f6;
            padding: 2px 4px;
            border-radius: 4px;
            font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
        }

        .ai-response blockquote {
            border-left: 4px solid #c7d2fe;
            padding-left: 16px;
            margin-left: 0;
            color: #4b5563;
            font-style: italic;
        }

        .user-message-content {
            background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 100%);
            color: white;
        }

        .input-container {
            background: rgba(255, 255, 255, 0.8);
            backdrop-filter: blur(10px);
            border: 1px solid rgba(229, 231, 235, 0.5);
        }

        .model-selector {
            transition: all 0.3s ease;
        }

        .model-selector:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
    </style>
</head>
<body class="min-h-screen flex flex-col">
<header class="bg-white shadow-sm">
    <div class="max-w-6xl mx-auto px-4 py-4 flex items-center justify-between">
        <div class="flex items-center">
            <div class="bg-gradient-to-r from-primary to-secondary w-10 h-10 rounded-lg flex items-center justify-center">
                <i class="fas fa-robot text-white text-xl"></i>
            </div>
            <div class="ml-3">
                <h1 class="text-xl font-bold text-gray-800">JYG-AI助手</h1>
            </div>
        </div>
        <div class="flex items-center space-x-4">
            <div class="model-selector bg-white border border-gray-200 rounded-lg px-3 py-2 flex items-center">
                <i class="fas fa-microchip text-secondary mr-2"></i>
                <p>模型：</p>
                <select id="modelSelect" style="padding: 2px;">
                    <option value="">加载中...</option>
                </select>
            </div>
            <div class="model-selector bg-white border border-gray-200 rounded-lg px-3 py-2 flex items-center">
                <i class="fas fa-microchip text-secondary mr-2"></i>
                <p>知识库：</p>
                <select id="knowledgeSelect" style="padding: 2px;">
                    <option value="">加载中...</option>
                </select>
            </div>
            <button class="flex items-center text-gray-600 hover:text-primary transition-colors">
                <i class="fas fa-cog mr-1"></i>
                <span class="text-sm">设置</span>
            </button>
        </div>
    </div>
</header>

<main class="flex-grow max-w-6xl mx-auto w-full px-4 py-6">

    <div id="messages" class="message-container rounded-2xl shadow-sm p-6 h-[70vh] overflow-y-auto mb-6">
        <div class="ai-message flex mb-6">
            <div class="flex-shrink-0 w-10 h-10 bg-gradient-to-br from-blue-100 to-purple-100 rounded-full flex items-center justify-center">
                <i class="fas fa-robot text-secondary text-lg"></i>
            </div>
            <div class="ml-4 max-w-[85%]">
                <div class="text-xs text-gray-500 mb-1">AI助手 · 现在</div>
                <div class="ai-response bg-white rounded-2xl rounded-tl-none px-5 py-4 shadow-sm border border-gray-100">
                    <p>👋 您好！我是您私家 AI助手，基于AI大模型。</p>
                    <p class="mt-2">您可以向我提问各种问题，例如：</p>
                    <ul class="list-disc pl-5 mt-2 space-y-1 text-gray-700">
                        <li>解释量子计算的基本原理</li>
                        <li>用JavaScript实现快速排序算法</li>
                        <li>帮我写一封辞职信</li>
                        <li>如何学习机器学习？</li>
                    </ul>
                    <p class="mt-3 text-sm text-gray-500">提示：按Enter发送，Shift+Enter换行</p>
                </div>
            </div>
        </div>
    </div>

    <div class="input-container rounded-2xl shadow-sm p-4">
        <form id="chat-form" class="flex items-end">
            <div class="flex-grow mr-4">
                <div class="relative">
                        <textarea
                                id="user-input"
                                placeholder="输入您的问题..."
                                rows="1"
                                class="w-full py-3 pl-4 pr-12 bg-white border border-gray-300 rounded-xl shadow-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent resize-none max-h-32"
                                autocomplete="off"
                        ></textarea>
                    <div class="absolute right-3 bottom-3 flex items-center">
                        <button
                                type="button"
                                id="clear-btn"
                                class="w-8 h-8 rounded-full text-gray-500 hover:text-gray-700 flex items-center justify-center transition-colors mr-1"
                                title="清空"
                        >
                            <i class="fas fa-times"></i>
                        </button>
                        <button
                                type="submit"
                                id="send-btn"
                                class="w-10 h-10 rounded-full bg-gradient-to-r from-primary to-secondary hover:from-primary-dark hover:to-secondary-dark flex items-center justify-center transition-all shadow-md"
                                title="发送"
                        >
                            <i class="fas fa-paper-plane text-white text-sm"></i>
                        </button>
                    </div>
                </div>
            </div>
            <div class="flex space-x-2">
                <button type="button" class="w-10 h-10 rounded-xl bg-white border border-gray-200 flex items-center justify-center text-gray-600 hover:text-primary hover:border-primary transition-colors" title="上传文件">
                    <i class="fas fa-paperclip"></i>
                </button>
                <button type="button" class="w-10 h-10 rounded-xl bg-white border border-gray-200 flex items-center justify-center text-gray-600 hover:text-primary hover:border-primary transition-colors" title="历史记录">
                    <i class="fas fa-history"></i>
                </button>
            </div>
        </form>
        <div id="error-container" class="mt-3 hidden">
            <div class="bg-red-50 border border-red-200 rounded-lg p-3 flex items-start">
                <i class="fas fa-exclamation-circle text-red-500 text-lg mt-0.5 mr-2"></i>
                <div>
                    <h3 class="font-medium text-red-800">请求出错</h3>
                    <p id="error-message" class="text-red-600 text-sm mt-1"></p>
                </div>
                <button id="retry-btn" class="ml-auto bg-red-100 hover:bg-red-200 text-red-700 px-3 py-1 rounded-full text-sm font-medium transition-colors">
                    重试
                </button>
            </div>
        </div>
    </div>

    <div class="mt-6 grid grid-cols-1 md:grid-cols-3 gap-4">
        <div class="bg-white rounded-xl p-4 shadow-sm border border-gray-100">
            <div class="flex items-center mb-3 space-x-3">
                <div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center mr-2">
                    <i class="fas fa-lightbulb text-blue-500"></i>
                </div>
                <h3 class="font-medium text-gray-800">知识库</h3>
                <p class="text-gray-600 text-sm">|</p>
                <a href="upload.html" class="w-22">
                    <p class="text-gray-600 text-sm hover:text-blue-500 transition-colors">点击上传</p>
                </a>
                <p class="text-gray-600 text-sm">|</p>
                <a href="review_knowlege.html" class="w-22">
                    <p class="text-gray-600 text-sm hover:text-blue-500 transition-colors">点击预览</p>
                </a>
            </div>
            <p class="text-gray-600 text-sm">支持上传和浏览专属知识库</p>
        </div>

        <div class="bg-white rounded-xl p-4 shadow-sm border border-gray-100">
            <div class="flex items-center mb-3 space-x-3">
                <div class="w-8 h-8 bg-purple-100 rounded-lg flex items-center justify-center mr-2">
                    <i class="fas fa-code text-purple-500"></i>
                </div>
                <h3 class="font-medium text-gray-800">GIT知识库</h3>
                <p class="text-gray-600 text-sm">|</p>
                <a href="git.html" class="w-22">
                    <p class="text-gray-600 text-sm hover:text-blue-500 transition-colors">点击上传</p>
                </a>
            </div>
            <p class="text-gray-600 text-sm">上传GIT知识库，解析代码让AI更懂你的代码</p>
        </div>

        <div class="bg-white rounded-xl p-4 shadow-sm border border-gray-100">
            <div class="flex items-center mb-3 space-x-3">
                <div class="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center mr-2">
                    <i class="fas fa-book text-green-500"></i>
                </div>
                <h3 class="font-medium text-gray-800">模型配置</h3>
            </div>
            <p class="text-gray-600 text-sm">配置更多类型AI模型，提高输出质量</p>
        </div>
    </div>
</main>

<footer class="py-6 mt-8 bg-white border-t">
    <div class="max-w-6xl mx-auto px-4 text-center">
        <p class="text-gray-600 text-sm">© 2023 AI助手 | 基于AI大模型 | 流式响应接口</p>
        <div class="mt-2 flex justify-center space-x-4">
            <a href="#" class="text-gray-500 hover:text-primary transition-colors text-sm">使用条款</a>
            <a href="#" class="text-gray-500 hover:text-primary transition-colors text-sm">隐私政策</a>
            <a href="#" class="text-gray-500 hover:text-primary transition-colors text-sm">GitHub</a>
            <a href="#" class="text-gray-500 hover:text-primary transition-colors text-sm">联系我们</a>
        </div>
    </div>
</footer>

<script>
    document.addEventListener('DOMContentLoaded', function() {
        const messagesContainer = document.getElementById('messages');
        const chatForm = document.getElementById('chat-form');
        const userInput = document.getElementById('user-input');
        const sendBtn = document.getElementById('send-btn');
        const clearBtn = document.getElementById('clear-btn');
        const errorContainer = document.getElementById('error-container');
        const errorMessage = document.getElementById('error-message');
        const retryBtn = document.getElementById('retry-btn');

        let currentEventSource = null;
        let currentAiMessageId = null;
        let currentAiResponse = '';
        let currentQuestion = '';

        // 加载模型列表
        loadModels();

        // 加载知识库列表
        loadKnowledgeBases();

        // 加载模型列表
        function loadModels() {
            fetch("http://localhost:8090/api/v1/ollama/models")
                .then(response => response.json())
                .then(res => {
                    const select = document.getElementById("modelSelect");
                    select.innerHTML = ""; // 清空原有选项
                    console.log("模型内容：", res)
                    if (res.code === "0000" && Array.isArray(res.data)) {
                        res.data.forEach(model => {
                            const option = document.createElement("option");
                            option.value = model;
                            option.textContent = model;
                            select.appendChild(option);
                        });
                    } else {
                        select.innerHTML = "<option>加载失败</option>";
                    }
                })
                .catch(err => {
                    console.error("加载模型失败:", err);
                    document.getElementById("modelSelect").innerHTML = "<option>加载失败</option>";
                });
        }

        // 加载知识库标签
        function loadKnowledgeBases() {
            fetch("http://localhost:8090/api/v1/rag/query_rag_tag_list")
                .then(response => response.json())
                .then(res => {
                    const select = document.getElementById("knowledgeSelect");
                    select.innerHTML = "";
                    if (res.code === "0000" && Array.isArray(res.data)) {
                        res.data.forEach(tag => {
                            const option = document.createElement("option");
                            option.value = tag;
                            option.textContent = tag;
                            select.appendChild(option);
                        });
                    } else {
                        select.innerHTML = "<option>加载失败</option>";
                    }
                })
                .catch(err => {
                    console.error("加载知识库失败:", err);
                    document.getElementById("knowledgeSelect").innerHTML = "<option>加载失败</option>";
                });
        }

        // 获取当前选中的模型和知识库
        function getSelectedModelAndKnowledge() {
            const model = document.getElementById("modelSelect").value;
            const knowledge = document.getElementById("knowledgeSelect").value;
            return { model, knowledge };
        }


        // 调整输入框高度
        function adjustTextareaHeight() {
            userInput.style.height = 'auto';
            userInput.style.height = Math.min(userInput.scrollHeight, 128) + 'px';
        }

        userInput.addEventListener('input', adjustTextareaHeight);

        // 处理用户输入
        chatForm.addEventListener('submit', function (e) {
            e.preventDefault();
            const message = userInput.value.trim();

            if (message) {
                // 隐藏错误信息
                errorContainer.classList.add('hidden');

                // 添加用户消息
                addUserMessage(message);

                // 保存当前问题
                currentQuestion = message;

                // 清空输入框并重置高度
                userInput.value = '';
                userInput.style.height = 'auto';

                // 禁用发送按钮
                sendBtn.disabled = true;
                sendBtn.classList.add('opacity-70');

                // 添加AI消息占位符
                currentAiMessageId = addAiMessage();

                // 调用API
                callAPI(message);
            }
        });

        // 支持Shift+Enter换行
        userInput.addEventListener('keydown', function (e) {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                chatForm.dispatchEvent(new Event('submit'));
            }
        });

        // 清空输入框
        clearBtn.addEventListener('click', function () {
            userInput.value = '';
            userInput.style.height = 'auto';
            userInput.focus();
        });

        // 重试按钮
        retryBtn.addEventListener('click', function () {
            errorContainer.classList.add('hidden');

            if (currentQuestion) {
                // 删除之前的AI响应
                if (currentAiMessageId) {
                    const aiMessage = document.getElementById(currentAiMessageId);
                    if (aiMessage) aiMessage.remove();
                }

                // 添加新的AI消息占位符
                currentAiMessageId = addAiMessage();

                // 禁用发送按钮
                sendBtn.disabled = true;
                sendBtn.classList.add('opacity-70');

                // 重新调用API
                callAPI(currentQuestion);
            }
        });

        // 添加用户消息
        function addUserMessage(message) {
            const timestamp = new Date().toLocaleTimeString([], {hour: '2-digit', minute: '2-digit'});

            const messageElement = document.createElement('div');
            messageElement.className = 'user-message flex justify-end mb-6';
            messageElement.innerHTML = `
                    <div class="max-w-[85%]">
                        <div class="text-xs text-gray-500 text-right mb-1">您 · ${timestamp}</div>
                        <div class="user-message-content rounded-2xl rounded-tr-none px-5 py-4 shadow-sm">
                            ${escapeHtml(message).replace(/\n/g, '<br>')}
                        </div>
                    </div>
                    <div class="flex-shrink-0 w-10 h-10 bg-gradient-to-br from-blue-200 to-purple-200 rounded-full flex items-center justify-center ml-4">
                        <i class="fas fa-user text-primary text-lg"></i>
                    </div>
                `;

            messagesContainer.appendChild(messageElement);
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
        }

        // 添加AI消息
        function addAiMessage() {
            const messageId = 'ai-msg-' + Date.now();

            const messageElement = document.createElement('div');
            messageElement.className = 'ai-message flex mb-6';
            messageElement.id = messageId;
            messageElement.innerHTML = `
                    <div class="flex-shrink-0 w-10 h-10 bg-gradient-to-br from-blue-100 to-purple-100 rounded-full flex items-center justify-center">
                        <i class="fas fa-robot text-secondary text-lg"></i>
                    </div>
                    <div class="ml-4 max-w-[85%]">
                        <div class="text-xs text-gray-500 mb-1">AI助手 · 正在输入</div>
                        <div class="ai-response bg-white rounded-2xl rounded-tl-none px-5 py-4 shadow-sm border border-gray-100">
                            <div class="typing-indicator-container">
                                <span class="typing-indicator"></span>
                                <span class="typing-indicator"></span>
                                <span class="typing-indicator"></span>
                            </div>
                        </div>
                    </div>
                `;

            messagesContainer.appendChild(messageElement);
            messagesContainer.scrollTop = messagesContainer.scrollHeight;

            return messageId;
        }

        // 调用API
        function callAPI(message) {
            // 关闭之前的连接（如果有）
            if (currentEventSource) {
                currentEventSource.close();
            }

            // 重置当前响应
            currentAiResponse = '';

            // 构建API URL
            const model = 'deepseek-r1:1.5b';
            const encodedMessage = encodeURIComponent(message);
            const apiUrl = `http://localhost:8090/api/v1/ollama/generate_stream?model=${model}&message=${encodedMessage}`;

            // 创建EventSource
            currentEventSource = new EventSource(apiUrl);

            currentEventSource.onmessage = function (event) {
                try {
                    const data = JSON.parse(event.data);

                    // 检查是否有内容
                    if (data.result && data.result.output && data.result.output.text) {
                        currentAiResponse += data.result.output.text;

                        // 更新AI消息
                        updateAiMessage(currentAiResponse);
                    }

                    // 检查是否结束
                    if (data.result && data.result.metadata && data.result.metadata.finishReason === 'stop') {
                        currentEventSource.close();
                        currentEventSource = null;

                        // 启用发送按钮
                        sendBtn.disabled = false;
                        sendBtn.classList.remove('opacity-70');

                        // 更新时间戳
                        updateAiTimestamp();
                    }
                } catch (error) {
                    console.error('解析错误:', error);
                    showError('解析响应时出错: ' + error.message);
                }
            };

            // 增强的错误处理
            currentEventSource.onerror = function (event) {
                // 打印详细的错误信息
                console.error('EventSource 错误:', event);

                let errorMsg = '连接出错';

                // 根据readyState判断错误类型
                if (currentEventSource.readyState === EventSource.CLOSED) {
                    errorMsg = '连接已关闭';
                } else if (currentEventSource.readyState === EventSource.CONNECTING) {
                    errorMsg = '正在尝试重新连接...';
                }

                // 显示详细的错误信息
                showError(`${errorMsg}。状态: ${event.target.readyState}`);

                currentEventSource.close();
                currentEventSource = null;

                // 启用发送按钮
                sendBtn.disabled = false;
                sendBtn.classList.remove('opacity-70');
            };
        }

        // 更新AI消息
        function updateAiMessage(content) {
            if (!currentAiMessageId) return;

            const messageElement = document.getElementById(currentAiMessageId);
            if (!messageElement) return;

            const responseElement = messageElement.querySelector('.ai-response');
            if (responseElement) {
                // 移除输入指示器
                const typingIndicator = responseElement.querySelector('.typing-indicator-container');
                if (typingIndicator) {
                    typingIndicator.remove();
                }

                // 渲染Markdown内容
                responseElement.innerHTML = marked.parse(content);

                // 确保滚动到底部
                messagesContainer.scrollTop = messagesContainer.scrollHeight;
            }
        }

        // 更新AI消息时间戳
        function updateAiTimestamp() {
            if (!currentAiMessageId) return;

            const messageElement = document.getElementById(currentAiMessageId);
            if (!messageElement) return;

            const timestampElement = messageElement.querySelector('.text-gray-500');
            if (timestampElement) {
                timestampElement.textContent = `AI助手 · ${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}` ;
            }
        }

        // 显示错误信息
        function showError(message) {
            // 更新错误消息
            errorMessage.textContent = message;
            errorContainer.classList.remove('hidden');
            if (currentAiMessageId) {
                const messageElement = document.getElementById(currentAiMessageId);
                if (messageElement) {
                    const responseElement = messageElement.querySelector('.ai-response');
                    if (responseElement) {
                        // 移除输入指示器
                        const typingIndicator = responseElement.querySelector('.typing-indicator-container');
                        if (typingIndicator) {
                            typingIndicator.remove();
                        }
                    }

                    responseElement.innerHTML = `
                                <div class="text-red-500">
                                    <i class="fas fa-exclamation-triangle mr-2"></i>请求失败
                                </div>
                                <div class="text-sm text-gray-600 mt-2">
                                ${escapeHtml(message)}
                                </div>
                                `;
                    // 更新时间戳
                    const timestampElement = messageElement.querySelector('.text-gray-500');
                    if (timestampElement) {
                        timestampElement.textContent = `AI助手 · ${new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}`;
                    }
                }
            }
        }
        // 简单的HTML转义
        function escapeHtml(unsafe) {
            return unsafe
                .replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&#039;");
        }

        // 初始调整输入框高度
        adjustTextareaHeight();
    });
</script>
</body>
</html>